import os,time

from typing import List, Tuple, Dict, Union, Optional, Any, Callable, Iterable, TypeVar, Generic
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys

from Common.comm_driver import Comm_Driver
from Configs.env import Env
from utils.handle_path import PollyPath
from utils.handle_yaml import get_yaml_data




class BasePage:
    """
    不同的页面要做的同样的事情
    0. 有个页面，输入网址
    0.5 定位元素
    1. 点击元素
    2. 输入文本
    3. 获取元素的文本
    4. 切换
    5. 上传
    6. 等待
    7. 封装键盘常用操作
    8. 封装具体frame切换
    9. 封装常用frame切换
    ...
    webdriver的核心技术：driver api
    """
    def __init__(self):
        self.driver = Comm_Driver().get_driver()
        # 1. 每个页面获取自己的locator
        self.locators = get_yaml_data(PollyPath.configs_path / 'allelements.yaml')[self.__class__.__name__]
        # 2. 把locators再次拆分： name和locator
        for element_name , locator in self.locators.items():
            setattr(self,element_name,locator)
    def open_url(self,url):
        '''
        1. 一个方法的实现 只有一行，就是调用另外一个方法
        2. 一个目的是为了 便于扩展(为今后的扩展做备用)
           示例： get(打开本地文件的时候 最好要加 file://)
        Args:
            url: 输入网址
        Returns: None
        '''
        self.driver.get(url=url)

    # 获取元素
    def get_element(self,
                    locator,
                    timeout=Env.TIMEOUT,
                    poll_frequency=Env.POLL_FREQUENCY
                    ,elements=False,desc=''):
        '''
        获取元素
        :param locator:
        :param timeout:超时时间
        :param poll_frequency:
        :param elements:
        :param desc:描述
        :return:无返回值
        '''

        try:
            if not elements:
                return WebDriverWait(self.driver,timeout=timeout,
                                     poll_frequency=poll_frequency).until(EC.visibility_of_element_located(locator))
            else:
                return WebDriverWait(self.driver, timeout=timeout,
                                     poll_frequency=poll_frequency).until(EC.visibility_of_all_elements_located(locator))
        except:
            from utils.handle_loguru import log
            log.error(f'元素:{desc}找不到')
            from time import strftime
            date = strftime('%Y%m%d%H%M%S')
            self.driver.save_screenshot(f'{PollyPath.screenshots_path}{os.sep}{desc}{date}.png')
            return False # 起到判断元素是否存在的功能

    def input_text(self,locator,text,append_flag=False,desc=''):
        '''
        在某个`元素`上输入`文本`
        Args:
            locator:  元素定位器  类似:'id','ls_username'
            text: 你要输入的文本
            append_flag: 是否追加输入的标记位
        Returns: None

        '''
        if append_flag:
            self.get_element(locator,desc=desc).send_keys(','+text)
        else:
            self.get_element(locator,desc=desc).clear()
            self.get_element(locator).send_keys(text)

    def click_element(self,locator,desc=''):
        self.get_element(locator,desc=desc).click()

    def get_element_text(self,locator,desc=''):
        time.sleep(3)
        return self.get_element(locator,desc=desc).text

    def get_element_texts(self,locator):
        return [element.text for element in self.get_element(locator,elements=True)]

    def __getitem__(self, item):  # ['username']
        return self.locators[item]  # self.locators['username']

    def is_that_url(self, url,
                    timeout=Env.TIMEOUT,
                    poll_frequency=Env.POLL_FREQUENCY):
        """
        判断是否是指定的URL ，加入显式等待，让你的判断更加稳定
        Args:
            url: 期待的URL地址，处理重定向的情况

        Returns: T/F

        """
        try:
            WebDriverWait(self.driver, timeout, poll_frequency).until(EC.url_to_be(url))
            return True
        except:
            return False

    def is_element_attr_has_text(self, locator, attr, text_, timeout=Env.TIMEOUT, poll_frequency=Env.POLL_FREQUENCY):
        try:
            WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
                EC.text_to_be_present_in_element_attribute(locator, attr, text_))
            return True
        except:
            return False

    # def switch_newest_window(self,num,timeout=Env.TIMEOUT, poll_frequency=Env.POLL_FREQUENCY):
    #     cur_handles = self.driver.window_handles
    #     try:
    #         WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
    #         EC.number_of_windows_to_be(num), message='窗口数错了')
    #         EC.w
    #         self.driver.switch_to.window(cur_handles[-1])
    #         return True
    #     except:
    #         return False
    def switch_newest_window(self):
        # old_handles = self.driver.window_handles
        # if WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
        #     EC.new_window_is_opened(old_handles),message='窗口数错了'):
        time.sleep(2)
        cur_win_handles = self.driver.window_handles
        self.driver.switch_to.window(cur_win_handles[-1])


    def operate_enter(self):
        # 利用键盘操作enter
        time.sleep(2)
        ActionChains(self.driver).send_keys(Keys.ENTER).perform()
        time.sleep(2)

    def operate_down(self):
        # 利用键盘操作enter
        time.sleep(2)
        ActionChains(self.driver).send_keys(Keys.ARROW_DOWN).perform()

    def close_cur_window(self):
        #关闭当前窗口
        time.sleep(2)
        self.driver.close()

    def operate_pagedown(self):
        # 利用键盘操作enter
        time.sleep(2)
        ActionChains(self.driver).send_keys(Keys.PAGE_DOWN).perform()

    def operate_doubleclick(self,ele):
        # 利用键盘操作双击
        time.sleep(2)
        ActionChains(self.driver).double_click(ele).perform()

    def switch_to_frame(self,locator, timeout=Env.TIMEOUT, poll_frequency=Env.POLL_FREQUENCY):
        #获取frame定位信息后，跳转到对应的frame
        try:
            WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
                EC.frame_to_be_available_and_switch_to_it(self.get_element(locator)), message='请检查元素')
            return True
        except:
            return False

    def frame_to_default(self):
        # 切换到默认frame
        self.driver.switch_to.default_content()
        time.sleep(2)

    def frame_to_parent(self):
        # 切换到父级frame
        self.driver.switch_to.parent_frame()

    def __getitem__(self, item): # ['username']
        return self.locators[item] # self.locators['username']

if __name__ == '__main__':
    test_flag = 1
    if test_flag ==1:
        # ImportError: cannot import name 'LoginPage' from partially initialized module 'pageObjs.loginPage' (most likely due to a circular import)
        # 循环导入
        from PageObject.loginPageToChandao import LoginPage
        test_loginpage = LoginPage().login_to_chandao(17751002401,'Fangjinmei625@')
        user_name = 'id','usernamea'

        test_loginpage.input_text(user_name,'admin',desc='用户名元素')

    '''
    下方为显式等待框架定义
    '''

    # from time import sleep
    # from selenium.webdriver.support.wait import WebDriverWait
    # from selenium.webdriver.support import expected_conditions as EC
    # from selenium.webdriver.common.by import By
    # from selenium import webdriver
    #
    # class Brouser:
    #     fox = webdriver.Firefox()
    #     wait = WebDriverWait(fox, 5)
    #
    #     def get_url(self, url):
    #         self.fox.get(url)
    #
    #     def title(self, value):
    #         """网页标题是否正确"""
    #         self.wait.until(EC.title_is(value), message='标题不匹配哦')
    #
    #     def contains_title(self, value):
    #         """判断是否包含指定、特定的文本"""
    #         self.wait.until(EC.title_contains(value))
    #
    #     def presence_located(self, value, *ele):
    #         """检查DOM上是否存在元素,不一定意味着元素是可见的"""
    #         el = self.wait.until(EC.presence_of_element_located(ele), message='没有发现期望的元素')
    #         el.send_keys(value)
    #
    #     def visibility_located(self, value, *ele):
    #         """检查元素是否存在于页面和可见"""
    #         el = self.wait.until(EC.visibility_of_all_elements_located(ele), message='没有发现期望的元素')
    #         el[0].send_keys(value)
    #
    #     def visibility_(self, *ele):
    #         """检查已知存在于页面的DOM是可见的"""
    #         el = self.wait.until(EC.visibility_of(self.fox.find_element(*ele)))
    #         el.click()
    #
    #     def url_be(self, url):
    #         """检查当前url的期望值。url是预期的url"""
    #         self.wait.until(EC.url_to_be(url))
    #
    #     def text_element(self, text, *ele):
    #         """对应的文本值是否正确"""
    #         self.wait.until(EC.text_to_be_present_in_element(ele, text), message='请检查定位的文本值')
    #
    #     def text_element_value(self, text, *ele):
    #         """对应的属性值是否正确"""
    #         self.wait.until(EC.text_to_be_present_in_element_value(ele, text), message='请检查对应的value属性值哦')
    #
    #     def frame_switch_to(self, *ele):
    #         """需要跑frame框架，就使用https://login.tmall.com/地址"""
    #         self.wait.until(EC.frame_to_be_available_and_switch_to_it(ele), message='请检查元素')
    #
    #     def invisibility_element(self, *ele):
    #         """元素时候不可见或异常"""
    #         self.wait.until(EC.invisibility_of_element_located(ele), message='请检查元素是否正确')
    #
    #     def element_clickable(self, *ele):
    #         """元素是否可以点击"""
    #         ele = self.wait.until(EC.element_to_be_clickable(ele), message='请检查元素是否可点击')
    #         ele.click()
    #
    #     def staleness_(self, *ele):
    #         """判断元素是否从DOM中移除"""
    #         self.wait.until_not(EC.staleness_of(self.fox.find_element(ele)))
    #
    #     def element_selected(self, *ele):
    #         """判断某个元素是否被选中"""
    #         self.wait.until(EC.element_to_be_selected(self.fox.find_element(*ele)), message="元素没有被选中，请检查元素")
    #
    #     def element_located_selected(self, *ele):
    #         """判断某个元素是否被选中"""
    #         self.wait.until(EC.element_located_to_be_selected(ele), message="元素没有被选中，请检查元素")
    #
    #     def element_selection_state(self, selected, *ele):
    #         """判断元素状态符合预期"""
    #         self.wait.until(EC.element_selection_state_to_be(self.fox.find_element(*ele), selected),
    #                         message="与预期值不匹配，请检查预期值")
    #
    #     def new_window(self, num):
    #         """窗口长度判断"""
    #         self.wait.until(EC.new_window_is_opened(num), message='窗口数错了')
    #
    #     def alert_present(self):
    #         return self.wait.until(EC.alert_is_present(), message='没有alert')
    #
    # if __name__ == '__main__':
    #     b = Brouser()
    #     # b.get_url('http://shop.aircheng.com/simple/login')
    #     # js = "window.open('https://www.baidu.com/')"
    #     # b.fox.execute_script(js)
    #     """
    #     b.get_url('https://baidu.com')
    #     b.fox.find_element(By.ID,'s-usersetting-top').click()
    #     b.fox.find_element(By.CLASS_NAME,'set').click()
    #     b.fox.find_element(By.ID,'s1_1').click()
    #     b.element_selected(By.ID, "s1_1")
    #     b.element_located_selected(By.ID,"s1_1")"""
    #     # b.get_url('https://login.tmall.com/')
    #     # b.url_be('http://shop.aircheng.com/simple/login')
    #     # b.presence_located('qingan', By.NAME, 'login_info')
    #     # b.visibility_located('qingan',By.NAME,'password')
    #     # b.visibility_(By.NAME, 'remember')
    #     # b.text_element('新用户',By.CLASS_NAME, 'reg_btn')
    #     # b.text_element_value('登录',By.CLASS_NAME,'input_submit')
    #     """
    #     # b.frame_switch_to(By.ID,'J_loginIframe')
    #     # t = b.fox.find_element(By.CLASS_NAME,'forgot-password-a-link').text
    #     # print(t)"""
    #     # b.invisibility_element(By.CLASS_NAME,'ddd')
    #     # b.element_clickable(By.NAME, 'remember')
    #     # b.staleness_(By.NAME,'remember')
    #     # b.fox.find_element(By.NAME,'remember').click()
    #     # b.element_selection_state(True,By.NAME,'remember')
    #     # headers = b.fox.current_window_handle
    #     # b.new_window([headers])
    #     from selenium.webdriver.common.action_chains import ActionChains
    #     b.fox.get('https://www.baidu.com')
    #     # 定位设置按钮
    #     res = b.fox.find_element_by_id('s-usersetting-top')
    #     # 鼠标悬停在设置的元素上
    #     ActionChains(b.fox).move_to_element(res).perform()
    #     # 点击搜索设置
    #     b.fox.find_element('class name', 'setpref').click()
    #     # 更换设置
    #     b.fox.find_element('id', 'nr_2').click()
    #     # 点击保存设置
    #     b.fox.find_element('link text', '保存设置').click()
    #     # 切换窗口
    #     a = b.alert_present()
    #     # 点击确定，确定与取消不能同时存在
    #     a.accept()